package com.lyh.notes.service.Impl;

import com.lyh.notes.mapper.CategoryMapper;
import com.lyh.notes.mapper.NoteMapper;
import com.lyh.notes.mapper.UserMapper;
import com.lyh.notes.model.base.ApiResponse;
import com.lyh.notes.model.base.Pagination;
import com.lyh.notes.model.dto.note.NoteQueryRequest;
import com.lyh.notes.model.entity.Category;
import com.lyh.notes.model.entity.Note;
import com.lyh.notes.model.entity.User;
import com.lyh.notes.model.vo.note.NoteVO;
import com.lyh.notes.scope.RequestScopeData;
import com.lyh.notes.service.*;
import com.lyh.notes.utils.ApiResponseUtil;
import com.lyh.notes.utils.MarkdownUtil;
import com.lyh.notes.utils.PaginationUtil;
import com.lyh.notes.utils.SearchUtils;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Log4j2
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private NoteMapper noteMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String NOTE_SEARCH_CACHE_KEY = "search:note:%s:%d:%d";
    private static final String USER_SEARCH_CACHE_KEY = "search:user:%s:%d:%d";
    private static final int CACHE_EXPIRE_TIME = 30; // 分钟

    @Autowired
    private UserService userService;


    @Autowired
    private NoteLikeService noteLikeService;

    @Autowired
    private CollectionNoteService collectionNoteService;

    @Autowired
    private RequestScopeData requestScopeData;

    @Autowired
    private CategoryService categoryService;


    @Override
    public ApiResponse<List<NoteVO>> searchNotes(String keyword, int page, int pageSize) {
        String cacheKey = String.format(NOTE_SEARCH_CACHE_KEY, keyword, page, pageSize);

        // 尝试从缓存获取
        List<NoteVO> cachedResult = (List<NoteVO>) redisTemplate.opsForValue().get(cacheKey);
        log.info("redis执行了查找");
        if (cachedResult != null) {

            return ApiResponseUtil.success("搜索成功", cachedResult);
        }

        // 处理关键词
        keyword = SearchUtils.preprocessKeyword(keyword);
        // 分页
        int offset= PaginationUtil.calculateOffset(page,pageSize);
        //得到notes
        List<Note>notes=noteMapper.searchNotes(keyword,pageSize,offset);
        int total=noteMapper.searchCountNotes(keyword);
        Pagination pagination=new Pagination(page,pageSize,total);
        if(notes==null){
            return ApiResponseUtil.success("当前无笔记");
        }
        // 得到所有笔记的作者并去重,之后得到他们的所需要的信息, 用HashMap映射作者ID和作者信息
        List<Long>usersId=notes.stream().map(Note::getAuthorId).distinct().toList();
        Map<Long,User>userMapByIds=userService.getUserMapByIds(usersId);

        // 得到所有笔记的类别并去重,之后得到他们的所需要的信息, 用HashMap映射类别ID和类别信息
        List<Integer>categoryIds=notes.stream().map(Note::getCategoryId).distinct().toList();
        Map<Integer, Category> categoryMapByIds =categoryService.getCategoryMapByIds(categoryIds);

        // 得到当前登录状态的用户所有点赞和收藏的笔记列表,用HashSet记录这些笔记的ID
        Set<Integer> userLikedNoteIds;
        Set<Integer> userCollectedNoteIds;
        List<Integer>noteIds=notes.stream().map(Note::getNoteId).toList();
        if (requestScopeData.isLogin() && requestScopeData.getUserId() != null) {
            Long currentUserId = requestScopeData.getUserId();
            userLikedNoteIds = noteLikeService.findUserLikedNoteIds(currentUserId, noteIds);
            userCollectedNoteIds = collectionNoteService.findUserCollectedNoteIds(currentUserId, noteIds);
        } else {  // 未登录状态直接设置为空集合
            userLikedNoteIds = Collections.emptySet();
            userCollectedNoteIds = Collections.emptySet();
        }
        try {
            List<NoteVO>noteVOS=notes.stream().map(note -> {
                        NoteVO noteVO=new NoteVO();
                        BeanUtils.copyProperties(note,noteVO);
                        User author= userMapByIds.get(note.getAuthorId());
                        if(author!=null){
                            NoteVO.SimpleAuthorVO simpleAuthorVO=new NoteVO.SimpleAuthorVO();
                            BeanUtils.copyProperties(author,simpleAuthorVO);
                            log.info(simpleAuthorVO.toString());
                            noteVO.setAuthor(simpleAuthorVO);
                        }
                        Integer categoryId=note.getCategoryId();
                        if(categoryId!=null){
                            NoteVO.SimpleCategoryVO simpleCategoryVO=new NoteVO.SimpleCategoryVO();
                            Category category=categoryMapByIds.get(categoryId);
                            simpleCategoryVO.setCategoryId(category.getCategoryId());
                            simpleCategoryVO.setCategoryName(category.getName());
                            log.info(simpleCategoryVO.toString());
                            noteVO.setCategory(simpleCategoryVO);
                        }
                        //是否点赞或收藏
                        NoteVO.UserActionsVO userActionsVO=new NoteVO.UserActionsVO();
                        userActionsVO.setIsCollected(userCollectedNoteIds.contains(note.getNoteId()));
                        userActionsVO.setIsLiked(userLikedNoteIds.contains(note.getNoteId()));
                        noteVO.setUserActions(userActionsVO);

                        if(MarkdownUtil.needCollapsed(noteVO.getContent())){
                            noteVO.setNeedCollapsed(true);
                            noteVO.setDisplayContent(MarkdownUtil.extractIntroduction(noteVO.getContent()));
                        }else{
                            noteVO.setNeedCollapsed(false);
                        }

                        return noteVO;
                    }
            ).toList();
            // 存入缓存
            testConnection();
            checkRedisMemory();
            redisTemplate.opsForValue().set(cacheKey, noteVOS, CACHE_EXPIRE_TIME, TimeUnit.MINUTES);

            return ApiResponseUtil.success("搜索成功", noteVOS,pagination);
            } catch (Exception e) {
            return ApiResponseUtil.error("获取笔记列表失败");
        }
    }

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    public void testConnection() {
        try (RedisConnection conn = redisConnectionFactory.getConnection()) {
            System.out.println("Redis 连接正常: " + conn.ping());  // 应输出 "PONG"
        } catch (Exception e) {
            System.err.println("Redis 连接失败: " + e.getMessage());
        }
    }

    public void checkRedisMemory() {
        Properties info = redisTemplate.getRequiredConnectionFactory().getConnection().info("memory");
        System.out.println("Redis内存使用情况: " + info.getProperty("used_memory_human"));
    }

    @Override
    public ApiResponse<List<User>> searchUsers(String keyword, int page, int pageSize) {
        try {
            String cacheKey = String.format(USER_SEARCH_CACHE_KEY, keyword, page, pageSize);
            
            // 尝试从缓存获取
            List<User> cachedResult = (List<User>) redisTemplate.opsForValue().get(cacheKey);
            if (cachedResult != null) {
                return ApiResponseUtil.success("搜索成功", cachedResult);
            }

            // 计算偏移量
            int offset = (page - 1) * pageSize;
            int count=userMapper.countByKeyword(keyword);
            Pagination pagination=new Pagination(page,pageSize,count);
            
            // 执行搜索
            List<User> users = userMapper.searchUsers(keyword, pageSize, offset);
            
            // 存入缓存
            redisTemplate.opsForValue().set(cacheKey, users, CACHE_EXPIRE_TIME, TimeUnit.MINUTES);
            
            return ApiResponseUtil.success("搜索成功", users,pagination);
        } catch (Exception e) {
            log.error("搜索用户失败", e);
            return ApiResponseUtil.error("搜索失败");
        }
    }


}
